Amazon Aurora DSQLのカスタムデータベースロールを使ってLambdaから接続してみた #AWSreInvent

Amazon Aurora DSQLのカスタムデータベースロールを使ってLambdaから接続してみた #AWSreInvent

Amazon Aurora DSQLにPostgresのロールとIAMロールを紐づけて接続する方法を試してみました
Clock Icon2024.12.05

はじめに

製造ビジネステクノロジー部の佐藤智樹です。

今回は、先日発表されたAurora DSQLのカスタムデータベースロールを使ってアクセスする方法を試してみます。実際の本番環境で使用する際は、Adminでなく個別に設定したDSQLのロールを使用することになります。より実践的な動かし方を確認してみました。また、ORMとしてはTypeORMを使用しています。

ソースコード

今回使用するソースコードは以下にアップロードしています。

https://github.com/tomoki10/dsql-lambda

やってみた

最初にCDKでLambdaとIAMロールをデプロイし、IAMロールのARNを確定させます。その後に、Aurora DSQLで今回使用するスキーマやロールに対してLambdaのIAMロールを設定します。最後にLambdaを実行してロールベースでAurora DSQLにアクセスできることを確認します。

CDKでLambdaをデプロイ

まず以下のCDK実装でLambdaを作成します。DB_USER(member)とSCHEMA(testschema)の部分は後ほど、DSQLでのロール/スキーマとしてそれぞれ使用します。以下をデプロイ後、Lambdaに紐づくロールのARNをメモしておきます。

lib/dsql-lambda-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as nodejs from 'aws-cdk-lib/aws-lambda-nodejs';

export class DsqlLambdaStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const dsqlLambda = new nodejs.NodejsFunction(this, 'DsqlLambda', {
      entry: 'src/index.ts',
      runtime: lambda.Runtime.NODEJS_LATEST,
      environment: {
        DB_USER: 'member',
        DATABASE: 'postgres',
        HOST_NAME: process.env.CLUSTER_ENDPOINT!, // HAK
        REGION: 'us-east-1',
        SCHEMA: 'testschema',
      },
      initialPolicy: [
        new iam.PolicyStatement({
          actions: ['dsql:DbConnect'],
          resources: [
            // See: https://docs.aws.amazon.com/aurora-dsql/latest/userguide/using-iam-condition-keys.html
            this.formatArn({
              service: 'dsql',
              region: 'us-east-1',
              resource: 'cluster',
              resourceName: process.env.CLUSTER_ID!,
            }),
          ],
        }),
      ],
    });

    // Create the role first and then register it with the DSQL role
    new cdk.CfnOutput(this, 'LambdaRoleArn', {
      value: dsqlLambda.role!.roleArn,
    });
  }
}

Lambdaのコードは以下になります。検証用のコードですがトークンはLambdaインスタンス内で使い回すように実装してみました。Adminと異なるのは、getDbConnectAuthTokenを使用している点とusernameに固有のロールmemberを使用している点です。

src/index.ts
import { DsqlSigner } from '@aws-sdk/dsql-signer';
import { DataSource } from 'typeorm';

const username = process.env.DB_USER;
const database = process.env.DATABASE;
const hostname = process.env.HOST_NAME!;
const region = process.env.REGION!;
const schema = process.env.SCHEMA!;

const generateToken = async (hostname: string, region: string) => {
  const signer = new DsqlSigner({
    hostname: hostname,
    region,
  });
  try {
    // NOTE: According to the official doc, it requires arguments
    //       but it does not work unless executed without arguments
    const token = await signer.getDbConnectAuthToken();
    return token;
  } catch (error) {
    console.error('Failed to generate token: ', error);
    throw error;
  }
};

let dataSource: DataSource;
const getDataSource = async (): Promise<DataSource> => {
  if (dataSource?.isInitialized) {
    return dataSource;
  }

  const password = await generateToken(hostname, region);
  dataSource = new DataSource({
    type: 'postgres',
    host: hostname,
    port: 5432,
    username,
    password,
    database,
    schema,
    ssl: true,
  });
  await dataSource.initialize();
  return dataSource;
};

export const handler = async () => {
  const ds = await getDataSource();
  const result = await ds.query('SELECT * FROM testschema.users');
  console.log('SQL result:', result);
};

上記を以下のコマンドで環境変数を設定後にデプロイします。

% export CLUSTER_ID='xxxxxxxxxx'
% export CLUSTER_ENDPOINT='xxxxxxxxxx.dsql.us-east-1.on.aws'
% npx cdk deploy

Outputs:
DsqlLambdaStack.LambdaRoleArn = arn:aws:iam::111122223333:role/DsqlLambdaStack-DsqlLambdaServiceRoleXXX

Aurora DSQLを設定

次にAurora DSQL側での設定を準備します。事前に以下などを参考にしてAurora DSQLクラスターを作成してください。

https://dev.classmethod.jp/articles/aurora-amazon-aurora-dsql/

CloudShellで以下のコマンドを実行して、Aurora DSQLへのAdmin権限ログイン用のパスワードを取得します。

% aws dsql generate-db-connect-admin-auth-token \
  --region us-east-1 \
  --expires 3600 \
  --hostname xxxxxxxxxx.dsql.us-east-1.on.aws

その後、パスワードを使ってAdmin権限でログインし、スキーマ/テーブル/データ設定を進めます。

% psql --host=xxxxxxxxxx.dsql.us-east-1.on.aws \
  --port=5432 \
  --dbname=postgres \
  --username=admin

postgres=> 
CREATE SCHEMA testschema
CREATE TABLE users(user_id int, name text);
INSERT INTO users (user_id, name) VALUES 
    (1, 'John Smith'),
    (2, 'Maria Garcia'),
    (3, 'Yuki Tanaka'),
    (4, 'David Wilson'),
    (5, 'Sarah Johnson');

次にロールの設定を進めます。Lambdaに紐づけたロールをAurora DSQLのロールに紐づけます。ここは以下のドキュメントを参考にしています。

https://docs.aws.amazon.com/aurora-dsql/latest/userguide/using-database-and-iam-roles.html

CREATE ROLE member WITH LOGIN;
AWS IAM GRANT member TO 'arn:aws:iam::111122223333:role/DsqlLambdaStack-DsqlLambdaServiceRoleXXX'; 
GRANT USAGE ON SCHEMA testschema TO member;
GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA testschema TO member;
exit

ここまで準備できたらLambdaの実行に移ります。

Lambdaを実行しAurora DSQLにmember権限でアクセス

最後に作成したmember権限で、Auora DSQLにアクセスできるか確認します。Lambdaコンソール上でテストを実行すると以下のようにAurora DSQLからデータが取得できるようになっていることが確認できます。

スクリーンショット 2024-12-05 0.41.06.png

所感

とにかくAurora DSQLを使ってみたかったので、少しだけ気になった内容を試してみました。もし本格利用を考える場合は必ずロールでの権限管理は必要になるので、是非参考にしてみてください!

参考情報

https://dev.classmethod.jp/articles/aurora-amazon-aurora-dsql/

https://dev.classmethod.jp/articles/reinvent2024-try-dsql-drizzle/

https://dev.classmethod.jp/articles/reinvent2024-try-dsql-drizzle-lambda/

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.